/**
 * Copyright 2008-2013, David George, Licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.magneato.mvc;

import java.io.StringReader;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.magneato.dto.Page;
import org.magneato.service.Repository;
import org.magneato.service.TemplateManager;
import org.magneato.utils.parsers.HashListContentHandler;
import org.magneato.utils.parsers.WikiParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Handles requests for the application home page.
 */
@Controller
public class MainController  {
	@Autowired
	private Repository repository;
	@Autowired
	private TemplateManager templateMgr;
	@Autowired
	private WikiParser wikiParser;
	
	private static final Logger _logger = LoggerFactory
			.getLogger(MainController.class);

	
	/**
	 * Main entry point. Will either display the relevant page if found or call
	 * a create page method.
	 * 
	 * Page names have the format: [/<namespace>]/url.htm
	 * 
	 * Namespace is optional. It is used to separate template and databases.
	 * 
	 * TODO: for comments we could do something like name.htm?c=nnn, this would then redirect to #n
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = { "/*.htm", "/*/*.htm"}, method = {RequestMethod.GET, RequestMethod.HEAD})
	public ModelAndView handleRequestInternal(HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		String uri = request.getServletPath();

		// we either have page not found or repository not found
		Page page = repository.get(uri);
		if (page == null) {
			/*
			 * page doesn't exist prompt user to create page
			 */
			String referrer = request.getHeader("Referer");
			if (referrer != null) {
				StringBuffer url = request.getRequestURL(); // full path
				int j = url.indexOf(uri);
				// check for -1
				String context = url.substring(0, j);
				if (referrer.startsWith(context)) {
					referrer = referrer.substring(j);
				}
			} else {
				referrer = "";
			}
			// need to remember page and parent in case we are not authenticated
			HttpSession session = request.getSession();
			session.setAttribute("redirect", "/createPageWizard.do?name=" + uri
					+ "&parent=" + referrer);

			// don't cache this page as it doesn't exist yet
			response.setHeader("Cache-Control", "no-cache");
			//response.setStatus(404);
			ModelAndView view = new ModelAndView("sys/pageNotFound", "name",
					uri);
			view.addObject("parent", referrer);
			return view;
		}

		page.setRepository(repository);
		page.setWikiParser(wikiParser);

		String nameSpace = page.getNameSpace();
		ModelAndView view = new ModelAndView(nameSpace + "/"
				+ page.getViewTemplate(), "page", page);

		// we automatically parse the page contents and add them to the template
		// context
		HashListContentHandler myHandler = parseContents(page.getContent(),
				wikiParser);
		view.addObject(myHandler.getRootName(), myHandler.getRootNode());

		Set<String> templateList = templateMgr.getTemplateGroup(nameSpace)
				.getTemplateList();
		view.addObject("templates", templateList);
		view.addObject("origin", getOrigin(request));
		return view;
	}

	/**
	 * This is called lazily as parsing is expensive and we maybe don't always
	 * want to do it. Maybe move this to Page DTO?
	 * 
	 * @param page
	 * @return HashListContentHandler Representation of a page contents as a
	 *         HashList
	 * @throws SAXException
	 * @throws ParserConfigurationException
	 */
	public final static HashListContentHandler parseContents(String contents,
			WikiParser wikiParser) throws ParserConfigurationException,
			SAXException {
		/*
		 * Expand XML contents to variable tree
		 */
		SAXParserFactory factory = SAXParserFactory.newInstance();
		SAXParser saxParser = factory.newSAXParser();
		HashListContentHandler myHandler = new HashListContentHandler(
				wikiParser);

		InputSource inStream = new InputSource();
		inStream.setCharacterStream(new StringReader(contents));
		try {
			saxParser.parse(inStream, myHandler);
		} catch (Exception e) {
			_logger.error("Problem parsing node contents " + contents + " reason " + e.getMessage());
		}

		return myHandler;
	}

	private final String getOrigin(HttpServletRequest request) {

		return request.getScheme() + "://" + request.getServerName() + ":"
				+ request.getServerPort() + request.getContextPath();

	}
}
